<template>
	<view class="x-select">
		<!-- 选择框 -->

		<u-input v-model="sLabel" type="select" :placeholder='props.placeholder' :class="showClearable?'isClearable':''"
			:clearable="props.clearable" @click="showPopup" v-bind='attrs'>
			<template #right-icon>
				<view class="right-icon-box">
					<text class="clearable-btn" v-if='showClearable' @tap.stop="clearableFu">×</text>
					<text class="drop-down">
						<!-- > -->
					</text>
				</view>
			</template>
		</u-input>
		<!-- <text class="clearable-btn" v-if='showClearable' @tap.stop="clearableFu">×</text> -->
		<!-- <view class="select-input" @tap="showPopup">
			<text class="placeholder" v-if="!selectedItem">{{ placeholder }}</text>
			<text class="value" v-else>{{ selectedItem[labelKey] }}</text>
			<text class="clearable-btn" v-if='clearable' @tap.stop="clearableFu">×</text>
			<text class="arrow">▼</text>
		</view> -->

		<!-- 底部弹出层 -->
		<view v-show="showOptions" class="mask" :class="{ 'mask-show': showOptions }" @tap="hidePopup">
			<view class="popup" :class="{ 'popup-show': showOptions }" @tap.stop>
				<!-- 顶部栏 -->
				<view class="popup-header">
					<text class="btn cancel" style="visibility: hidden" @tap="hidePopup">取消</text>
					<text class="title">{{ placeholder }}</text>
					<text class="btn" :style="{visibility: props.multiple?'visible':'hidden'}"
						@tap="hidePopup">确定</text>
				</view>

				<!-- 搜索框 -->
				<view class="search-box" v-if="searchable">
					<u-search placeholder="搜索关键词" v-model="searchText" :show-action="false" shape='square'
						@input='onSearch'></u-search>
					<!-- <view class="search-input-box">
						<text class="search-icon">
							🔍
						</text>
						<input class="search-input" v-model="searchText" placeholder="搜索关键词" @input="onSearch" />
					</view> -->
				</view>

				<scroll-view class="popup-content" scroll-y :scroll-with-animation="true" :scroll-top="scrollToTop"
					@scroll="handleScroll" @scrolltolower="handleScrollToLower">
					<!-- 加载中状态 -->
					<view v-if="loading && visibleOptions.length === 0" class="loading-state">
						<text class="loading-dot">●</text>
						<text class="loading-dot">●</text>
						<text class="loading-dot">●</text>
						<text class="loading-text">加载中</text>
					</view>

					<!-- 空状态提示 -->
					<view v-else-if="!loading && visibleOptions.length === 0" class="empty">
						<text class="empty-text">暂无数据</text>
					</view>

					<!-- 选项列表 -->
					<template v-else>
						<view class="option" v-for="(item, index) in visibleOptions" :key="`${item[valueKey]}-${index}`"
							:class="{ active: isSelected(item),isDisabled:item.disabled }" @tap="selectOption(item)">
							{{ item[labelKey] }}
							<text class="check" v-if="isSelected(item)">
								<text class="check-circle">●</text>
							</text>
						</view>

						<!-- 底部加载状态和无更多数据提示只在remote模式下显示 -->
						<template v-if="remote">
							<!-- 底部加载状态 -->
							<view v-if="loading" class="loading">
								<text class="loading-dot">●</text>
								<text class="loading-dot">●</text>
								<text class="loading-dot">●</text>
							</view>
							<!-- 无更多数据 -->
							<view v-if="!hasMore && !loading && filteredOptions.length > 0" class="no-more">
								没有更多了
							</view>
						</template>
					</template>
				</scroll-view>
				<!-- 底部安全区域 -->
				<view class="safe-area-inset-bottom"></view>
			</view>
		</view>
	</view>
</template>

<script setup>
	import {
		ref,
		computed,
		onMounted,
		onUnmounted,
		watch,
		useAttrs,
		toRaw
	} from 'vue'
	const attrs = useAttrs()
	const props = defineProps({
		// 选中值
		modelValue: {
			type: [String, Number, Object, Array],
			default: null
		},
		// 标签键名
		labelKey: {
			type: String,
			default: 'label'
		},
		// 值键名
		valueKey: {
			type: String,
			default: 'value'
		},
		// 占位符
		placeholder: {
			type: String,
			default: '请选择'
		},
		// 是否可搜索
		searchable: {
			type: Boolean,
			default: false
		},
		// 每页数量
		pageSize: {
			type: Number,
			default: 10
		},
		// 选项高度
		itemHeight: {
			type: Number,
			default: 88
		},
		// 是否远程搜索
		remote: {
			type: Boolean,
			default: false
		},
		// 选项数据
		options: {
			type: Array,
			default: () => []
		},
		// 弹出层内容区域高度
		popupHeight: {
			type: String,
			default: '600rpx'
		},
		// 是否从接口加载选中值
		loadSelected: {
			type: Boolean,
			default: false
		},
		// 是否可清除
		clearable: {
			type: Boolean,
			default: false
		},
		// 选择框宽度
		inputWidth: {
			type: String,
			default: '100%'
		},
		// 选择框高度
		inputHeight: {
			type: String,
			default: '80rpx'
		},
		// 选择框内边距
		inputPadding: {
			type: String,
			default: '0 20rpx'
		},
		// 选择框字体大小
		inputFontSize: {
			type: String,
			default: '28rpx'
		},
		// 选择框圆角
		inputRadius: {
			type: String,
			default: '8rpx'
		},
		// 是否多选
		multiple: {
			type: Boolean,
			default: false
		}
	})

	const emit = defineEmits(['update:modelValue', 'change', 'load-data', 'search', 'load-selected'])

	const sLabel = computed(() => {
		if (isEmpty(selectedItem.value)) return
		let label = selectedItem.value.map(e => e[props.labelKey]).toString()
		return label
	})

	const showClearable = computed(() => {
		return props.clearable && !isEmpty(props.modelValue)
	})

	// 显示状态
	const showOptions = ref(false)
	// 搜索文本
	const searchText = ref('')
	// 是否滚动到顶部
	const scrollToTop = ref(0)
	// 加载状态
	const loading = ref(false)
	// 选项数据
	const options = ref([])
	// 当前选中项
	const selectedItem = ref([])
	// 当前页码
	const currentPage = ref(1)

	// 根据modelValue构建默认选中项
	const createDefaultSelectedItem = (value) => {
		if (isEmpty(value)) return []
		return value.map(e => {
			return {
				[props.labelKey]: e,
				[props.valueKey]: e
			}
		})
	}

	const mValue = computed(() => {
		return strToArr(props.modelValue)
	})

	// 过滤后的选项
	const filteredOptions = computed(() => {
		// 远程搜索时不做本地过滤
		if (props.remote) return options.value

		// 本地搜索
		if (!searchText.value) return props.options
		return props.options.filter(item =>
			item[props.labelKey].toLowerCase().includes(searchText.value.toLowerCase())
		)
	})

	// 计算可视区域选项
	const visibleOptions = computed(() => {
		return filteredOptions.value
	})

	// 是否还有更多数据
	const hasMore = computed(() => {
		if (!props.remote) return false
		// 最后一页返回的数据条数小于pageSize，说明没有更多数据了
		const lastPageSize = options.value.length % props.pageSize
		return !loading.value && (!lastPageSize || lastPageSize === props.pageSize)
	})

	// 判断是否选中
	const isSelected = (item) => {
		if (props.multiple) {
			// 多选模式
			return selectedItem.value.some(e => e[props.valueKey] == item[props.valueKey])
		} else {
			// 单选模式
			if (selectedItem.value.length === 0) return false
			return selectedItem.value[0][props.valueKey] == item[props.valueKey]
		}
	}

	// 显示弹出层
	const showPopup = () => {
		showOptions.value = true
		if (isEmpty(options.value)) {
			initOptions()
		}
		// initOptions()
	}

	// 清除数据
	const clearableFu = () => {
		emit('update:modelValue', undefined)
		emit('change', undefined)
	}

	function initOptions() {
		// 远程搜索模式才需要加载数据
		if (props.remote) {
			currentPage.value = 1
			loading.value = true
			emit('load-data', {
				keyword: searchText.value,
				page: 1,
				pageSize: props.pageSize,
				isSearch: true,
				callback: (data) => {
					options.value = data
					loading.value = false
					// 在新数据中查找当前选中项
					// const found = data.filter(item =>
					// 	mValue.value.some(e => e == item[props.valueKey])
					// 	// mValue.value.includes(item[props.valueKey])
					// )
					// if (!isEmpty(found)) {
					// 	selectedItem.value = found
					// } else if (mValue.value.length > 0) {
					// 	// 如果在新数据中找不到，但有值，保持当前选中项不变
					// 	selectedItem.value = isEmpty(selectedItem.value) ? createDefaultSelectedItem(mValue
					// 		.value) : selectedItem.value
					// }
				}
			})
		} else {
			options.value = props.options
			// 在本地数据中查找当前选中项
			// const found = props.options.filter(item =>
			// 	mValue.value.some(e => e == item[props.valueKey])
			// 	// mValue.value.includes(item[props.valueKey])
			// )
			// if (!isEmpty(found)) {
			// 	selectedItem.value = found
			// } else if (mValue.value.length > 0) {
			// 	// 如果在本地数据中找不到，但有值，保持当前选中项不变
			// 	selectedItem.value = isEmpty(selectedItem.value) ? createDefaultSelectedItem(mValue.value) : selectedItem
			// 		.value
			// }
		}

	}

	// 隐藏弹出层
	const hidePopup = () => {
		showOptions.value = false
	}

	// 选择选项
	const selectOption = (item) => {
		if (item.disabled) return
		if (props.multiple) {
			// 根据id判断当前点击的是否被选中
			const isS = selectedItem.value.findIndex(obj => obj[props.valueKey] == item[props.valueKey])
			if (isS >= 0) {
				selectedItem.value.splice(isS, 1)
			} else {
				selectedItem.value.push(item)
			}
			emit('update:modelValue', selectedItem.value.map(e => e[props.valueKey]))
		} else {
			emit('update:modelValue', item[props.valueKey])
			selectedItem.value = [item]
			hidePopup()
		}
		emit('change', selectedItem.value)
	}

	const handleScroll = (e) => {
		// scrollToTop.value = e.detail.scrollTop
	}

	// 搜索处理
	const onSearch = (val) => {
		searchText.value = val
		// 远程搜索
		if (props.remote) {
			currentPage.value = 1
			options.value = []
			loading.value = true
			emit('load-data', {
				keyword: searchText.value,
				page: currentPage.value,
				pageSize: props.pageSize,
				isSearch: true,
				callback: (data) => {
					options.value = data
					scrollToTop.value = 0
					loading.value = false
				}
			})
		}
	}

	// 滚动到底部
	const handleScrollToLower = () => {
		// 非远程模式不处理加载更多
		if (!props.remote) return

		if (loading.value || !hasMore.value) return

		loading.value = true
		currentPage.value++

		emit('load-data', {
			keyword: searchText.value,
			page: currentPage.value,
			pageSize: props.pageSize,
			isSearch: false,
			callback: (data) => {
				// 追加数据
				options.value = [...options.value, ...data]
				loading.value = false
				// 如果返回的数据条数小于pageSize，说明没有更多数据了
				if (data.length < props.pageSize) {
					hasMore.value = false
				}
			}
		})
	}

	// 点击外部关闭
	const closeOnClickOutside = (e) => {
		if (!e.target.closest('.x-select')) {
			showOptions.value = false
		}
	}

	// 判断非空
	const isEmpty = (value) => {
		// null 或 undefined
		if (value === null || typeof value === 'undefined') {
			return true;
		}
		// 数字 0、NaN 不认为是空
		if (typeof value === 'number' && !isNaN(value)) {
			return false;
		}
		// 布尔值：false 不认为是空
		if (typeof value === 'boolean') {
			return false;
		}
		// 字符串：仅空格也认为是空
		if (typeof value === 'string') {
			return value.trim() === '';
		}
		// 数组或对象
		if (typeof value === 'object') {
			// 数组
			if (Array.isArray(value)) {
				return value.length === 0;
			}
			// 对象
			return Object.keys(value).length === 0;
		}
		// 其他情况（如 function）不认为是空
		return false;
	};

	//转数组
	function strToArr(val, rule = ',') {
		// 处理 null 或 undefined
		if (val === null || val === undefined) {
			return []
		}

		// 如果已经是数组，直接返回
		if (Array.isArray(val)) {
			return val
		}

		// 判断是否为基本类型
		const type = typeof val

		if (type === 'number') {
			if (isNaN(val)) {
				return [] // 或者 throw new TypeError('NaN is not allowed');
			}
			val = val.toString()
		} else if (type === 'boolean') {
			val = val.toString()
		} else if (type !== 'string') {
			// 非字符串/数字/布尔值等非基础类型，抛出错误或返回空
			return [] // 或者 throw new TypeError(`Unsupported type: ${type}`);
		}

		// 确保 rule 是字符串或正则表达式
		if (typeof rule !== 'string' && !(rule instanceof RegExp)) {
			rule = ','
		}

		return val.split(rule)
	}

	// 监听点击事件
	onMounted(() => {
		// 如果配置了从接口加载选中值则不初始化
		if (!props.loadSelected) {
			initOptions()
		} else {
			initLoadSelected(props.modelValue)
		}

		document?.addEventListener('click', closeOnClickOutside)
	})

	onUnmounted(() => {
		document?.removeEventListener('click', closeOnClickOutside)
	})

	defineExpose({
		initOptions,
		sLabel,
		selectedItem,
		showPopup,
		clearableFu
	})

	function initLoadSelected(value) {
		if (props.loadSelected && !showOptions.value && !isEmpty(value)) {
			emit('load-selected', {
				value: value,
				callback: (arr) => {
					// console.log('arr============》', arr);
					if (!isEmpty(arr)) {
						selectedItem.value = arr
					} else {
						// 如果接口也没有找到，则创建默认选中项
						selectedItem.value = createDefaultSelectedItem(strToArr(value))
					}
				}
			})
		}
	}
	watch(() => options.value, () => {
		// 在当前options中查找
		const found = options.value.filter(item =>
			mValue.value.some(e => e == item[props.valueKey])
		)
		if (!isEmpty(found)) {
			selectedItem.value = found
			return
		} else if (mValue.value.length > 0) {
			selectedItem.value = isEmpty(selectedItem.value) ? createDefaultSelectedItem(mValue.value) :
				selectedItem
				.value
		}
	}, {
		deep: true
	})
	// 监听modelValue变化
	watch(() => props.modelValue, (newValue) => {
		// 如果值为空，清空选中项
		if (isEmpty(newValue)) {
			selectedItem.value = []
			return
		}

		// 在当前options中查找
		// const found = options.value.filter(item =>
		// 	strToArr(newValue).some(e => e == item[props.valueKey])
		// 	// item[props.valueKey] == newValue
		// )
		// if (!isEmpty(found)) {
		// 	selectedItem.value = found
		// 	return
		// }

		// 如果配置了从接口加载选中值
		// if (props.loadSelected && !showOptions.value) {
		// 	initLoadSelected(newValue)
		// 	return
		// }

		// 如果在当前数据中找不到，但有值，则创建一个默认选中项
		// if (!isEmpty(newValue)) {
		// 	selectedItem.value = createDefaultSelectedItem(strToArr(newValue))
		// }
	}, {
		immediate: true
	})
</script>
<style>
	.x-select {
		position: relative;
		width: v-bind(inputWidth);
		display: inline-block;
	}

	.select-input {
		height: v-bind(inputHeight);
		padding: v-bind(inputPadding);
		border: 1rpx solid #ddd;
		border-radius: v-bind(inputRadius);
		display: flex;
		align-items: center;
		justify-content: space-between;
		background: #fff;
	}

	.placeholder {
		flex: 1;
		color: #999;
		font-size: v-bind(inputFontSize);
	}

	.value {
		flex: 1;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
		font-size: v-bind(inputFontSize);
	}

	.arrow {
		font-size: calc(v-bind(inputFontSize) * 0.85);
		color: #666;
		margin-left: 20rpx;
	}


	.isClearable :deep([type="select"]) {
		padding-right: 0.5rem;
	}

	.right-icon-box {
		display: flex;
		justify-content: center;
		align-items: center;
	}

	.clearable-btn {
		background-color: #c0c4cc;
		color: #fff;
		border-radius: 500px;
		display: flex;
		justify-content: center;
		/* align-items: center; */
		font-size: 0.85rem;
		width: 1.2rem;
		height: 1.2rem;
		line-height: 1.2rem;
		margin-right: 8rpx;
		z-index: 6;
	}

	/* 	.clearable-btn {
		position: absolute;
		top: 50%;
		right: 1.8em;
		transform: translateY(-50%);
		background-color: #c0c4cc;
		color: #fff;
		border-radius: 500px;
		display: flex;
		justify-content: center;
		align-items: center;
		font-size: calc(v-bind(inputFontSize) * 0.85);
		width: calc(v-bind(inputFontSize) * 1.2);
		height: calc(v-bind(inputFontSize) * 1.2);
	} */

	.drop-down {
		display: inline-block;
		color: #c0c4cc;
		transform: rotate(45deg);
		-ms-transform: rotate(45deg);
		/* IE 9 */
		-webkit-transform: rotate(45deg);
		/* Safari and Chrome */
	}

	.drop-down:after {
		display: block;
		content: '';
		width: 18rpx;
		height: 18rpx;
		border-top: #c0c4cc 4rpx solid;
		border-right: #c0c4cc 4rpx solid;
	}

	/* 	.clearable-btn {
		background-color: #939393;
		color: #fff;
		border-radius: 500px;
		display: flex;
		justify-content: center;
		align-items: center;
		font-size: calc(v-bind(inputFontSize) * 0.85);
		width: calc(v-bind(inputFontSize) * 1.2);
		height: calc(v-bind(inputFontSize) * 1.2);
	} */

	.mask {
		position: fixed;
		top: 0;
		left: 0;
		right: 0;
		bottom: 0;
		background: rgba(0, 0, 0, 0);
		z-index: 999;
		transition: background-color 0.3s;
		opacity: 0;
		visibility: hidden;
	}

	.mask-show {
		background: rgba(0, 0, 0, 0.4);
		opacity: 1;
		visibility: visible;
	}

	.popup {
		position: fixed;
		left: 0;
		right: 0;
		bottom: 0;
		background: #fff;
		border-radius: 24rpx 24rpx 0 0;
		z-index: 1000;
		max-height: 70vh;
		display: flex;
		flex-direction: column;
		transform: translateY(100%);
		transition: transform 0.3s;
	}

	.popup-show {
		transform: translateY(0);
	}

	.popup-header {
		height: 88rpx;
		display: flex;
		align-items: center;
		justify-content: space-between;
		padding: 0 30rpx;
		border-bottom: 1rpx solid #eee;
	}

	.btn {
		padding: 20rpx;
		font-size: 28rpx;
		min-width: 56rpx;
		text-align: center;
	}

	.title {
		font-size: 32rpx;
		font-weight: 500;
		color: #333;
	}

	.popup-content {
		height: v-bind(popupHeight);
		background: #fff;
	}

	.search-box {
		padding: 20rpx;
		border-bottom: 1rpx solid #eee;
		background: #fff;
	}

	.search-input-box {
		position: relative;
		display: flex;
		align-items: center;
	}

	.search-icon {
		position: absolute;
		left: 20rpx;
		color: #999;
		font-size: 28rpx;
	}

	.search-input {
		text-align: center;
		height: 60rpx;
		padding: 0 20rpx 0 60rpx;
		border: 1rpx solid #ddd;
		border-radius: 4rpx;
		font-size: 28rpx;
		background: #f5f5f5;
		width: 100%;
	}

	.option {
		width: 100%;
		padding: 0 30rpx;
		height: 88rpx;
		line-height: 88rpx;
		box-sizing: border-box;
		overflow: hidden;
		text-overflow: ellipsis;
		white-space: nowrap;
		display: flex;
		align-items: center;
		justify-content: space-between;
		font-size: 28rpx;
		color: #333;
		background: #fff;
		border-bottom: 1rpx solid #eee;
	}

	.option:active {
		background-color: #f8f8f8;
	}

	.option.active {
		color: var(--maiColor, #2979ff);
		font-weight: 500;
		background-color: var(--maiColor-10, #f2faff);
	}

	.option.isDisabled {
		color: #7a7a7a;
		background-color: #f3f3f3;
	}

	.check {
		/* #2979ff */
		color: var(--maiColor, #2979ff);
		font-size: 32rpx;
		display: flex;
		align-items: center;
	}

	.check-circle {
		width: 32rpx;
		height: 32rpx;
		line-height: 32rpx;
		text-align: center;
		font-size: 20rpx;
	}

	.loading {
		text-align: center;
		padding: 20rpx;
		color: #999;
		font-size: 24rpx;
		display: flex;
		justify-content: center;
		gap: 8rpx;
		background: #fff;
	}

	.loading-dot {
		animation: loading 1s infinite;
	}

	.loading-dot:nth-child(2) {
		animation-delay: 0.2s;
	}

	.loading-dot:nth-child(3) {
		animation-delay: 0.4s;
	}

	@keyframes loading {

		0%,
		100% {
			opacity: 0.3;
		}

		50% {
			opacity: 1;
		}
	}

	.safe-area-inset-bottom {
		height: constant(safe-area-inset-bottom);
		height: env(safe-area-inset-bottom);
		background-color: #fff;
	}

	.no-more {
		text-align: center;
		padding: 20rpx;
		color: #999;
		font-size: 24rpx;
		background: #fff;
	}

	/* 加载中状态 */
	.loading-state {
		display: flex;
		align-items: center;
		justify-content: center;
		height: calc(v-bind(popupHeight) / 2);
		color: #999;
		gap: 8rpx;
	}

	.loading-text {
		font-size: 28rpx;
		margin-left: 8rpx;
	}

	.loading-state .loading-dot {
		animation: loading 1s infinite;
	}

	.loading-state .loading-dot:nth-child(2) {
		animation-delay: 0.2s;
	}

	.loading-state .loading-dot:nth-child(3) {
		animation-delay: 0.4s;
	}

	/* 空状态样式 */
	.empty {
		display: flex;
		align-items: center;
		justify-content: center;
		height: calc(v-bind(popupHeight) / 2);
		color: #999;
	}

	.empty-text {
		font-size: 28rpx;
	}
</style>